/*
 * Copyright (c) 2007, TopCoder, Inc. All rights reserved.
 */

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using TopCoder.Util.Calendar.Entry;

namespace TopCoder.WinForms.Controls.CalendarView.Views
{
    /// <summary>
    /// <para>
    /// Extension of <see cref="CalendarEntryPopupPanel"/> that renders the desired columns
    /// of a <see cref="CalendarEntry"/> in the Day View in a popup if the panel display is truncated.
    /// </para>
    /// <para>
    /// The <see cref="FullEntryPopupPanel.Columns"/> property will determine which columns will appear in the popup.
    /// All data will not be truncated and shown in its entirety.
    /// </para>
    /// </summary>
    /// <remarks>Thread Safety: This class is mutable and not thread-safe.</remarks>
    /// <author>Ghostar</author>
    /// <author>yext</author>
    /// <author>argolite</author>
    /// <author>alex.dolin</author>
    /// <version>1.1</version>
    /// <copyright>Copyright (c) 2007, TopCoder, Inc. All rights reserved.</copyright>
    public class FullEntryPopupPanel : CalendarEntryPopupPanel
    {
        /// <summary>
        /// Represents the names of columns to display. A null, by default, means all available columns will be used
        /// as they are found in the entry. An empty list means no columns will be displayed, and any given list will
        /// indicate the desired columns. If a given column is not found in the entry, it is ignored.
        /// The list is managed in the Columns property.
        /// </summary>
        private IList<string> columns;

        /// <summary>
        /// Names of the columns to display. If columns is null then
        /// this field will hold default columns.
        /// </summary>
        private IList<string> viewColumns;

        /// <summary>
        /// Measured total width.
        /// </summary>
        private float totalWidth;

        /// <summary>
        /// Measured height of the header row.
        /// </summary>
        private float headerRowHeight;

        /// <summary>
        /// Measured height of the normal row.
        /// </summary>
        private float measuredHeight;

        /// <summary>
        /// Measured width of each column.
        /// </summary>
        private float[] columnsWidth;

        /// <summary>
        /// Creates a new instance of this class.
        /// </summary>
        /// <param name="entry">The entry for this panel.</param>
        /// <param name="truncated">The flag whether the data is truncated.</param>
        /// <param name="calendarView">The parent calendar view.</param>
        /// <param name="destinationViewName">The destination view's name
        /// for the calendar view control.</param>
        /// <param name="dateOfInterest">The date around which to wrap the destination view.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="entry"/>
        /// or <paramref name="calendarView"/> is null.</exception>
        public FullEntryPopupPanel(CalendarEntry entry, bool truncated, AbstractCalendarView calendarView,
                                   string destinationViewName, DateTime dateOfInterest)
            : base(entry, truncated, calendarView, destinationViewName, dateOfInterest)
        {
        }

        /// <summary>
        /// Represents the names of columns to display. A null, by default, means all available columns will be used
        /// as they are found in the entry. An empty list means no columns will be displayed, and any given list will
        /// indicate the desired columns. If a given column is not found in the entry, it is ignored.
        /// </summary>
        /// <value>The names of columns to display.</value>
        /// <exception cref="ArgumentException">If set to a list with null/empty strings.</exception>
        public IList<string> Columns
        {
            get
            {
                return Helper.GetStringListCopy(columns);
            }
            set
            {
                Helper.CheckStringListForNullAndEmptyElements(value, "Columns");
                columns = Helper.GetStringListCopy(value);
            }
        }

        /// <summary>
        /// Processes the display panel paint event.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The event, containing the graphic.</param>
        protected override void OnPopupPaint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            // The header row background color:
            g.FillRectangle(DailyCalendarView.headerBackBrush, 0, 0, totalWidth,
                            headerRowHeight + DailyCalendarView.PADDING_TOP + DailyCalendarView.PADDING_BOTTOM);

            // The header and value strings:
            float x = DailyCalendarView.PADDING_LEFT;
            for (int columnIndex = 0; columnIndex < columnsWidth.Length; columnIndex++)
            {
                g.DrawString(viewColumns[columnIndex], DailyCalendarView.headerFont, DailyCalendarView.headerBrush,
                             x, DailyCalendarView.PADDING_TOP);

                g.DrawRectangle(DailyCalendarView.itemBorderPen, x - DailyCalendarView.PADDING_LEFT,
                                headerRowHeight + DailyCalendarView.PADDING_TOP + DailyCalendarView.PADDING_BOTTOM,
                                columnsWidth[columnIndex] + DailyCalendarView.PADDING_LEFT +
                                DailyCalendarView.PADDING_RIGHT,
                                measuredHeight + DailyCalendarView.PADDING_TOP + DailyCalendarView.PADDING_BOTTOM);

                g.DrawString(DailyCalendarView.GetColumnValue(Entry, viewColumns[columnIndex]),
                             DailyCalendarView.itemFont, DailyCalendarView.itemBrush, x,
                             headerRowHeight + 2*DailyCalendarView.PADDING_TOP + DailyCalendarView.PADDING_BOTTOM);

                x += columnsWidth[columnIndex] + DailyCalendarView.PADDING_RIGHT + DailyCalendarView.PADDING_LEFT;
            }
        }

        /// <summary>
        /// <para>Displays the popup on the screen.</para>
        /// <para>Implementations must check whether the popup is required,
        /// determine size of the popup and then show it.</para>
        /// <para>Method <see cref="PopupPanel.ShowPopup"/> should be used to display
        /// the popup in default position. Implementations should create and use
        /// <see cref="Graphics"/> of the <paramref name="display"/> panel to measure the size.</para>
        /// </summary>
        /// <param name="display">The panel that will hold all drawn data.</param>
        /// <param name="popup">The popup control that holds the panel data.</param>
        protected override void DrawPanel(Panel display, ToolStripDropDown popup)
        {
            if(Truncated)
            {
                using(Graphics g = display.CreateGraphics())
                {
                    if (columns == null)
                    {
                        viewColumns = DailyCalendarView.defaultColumns;
                    }
                    else
                    {
                        viewColumns = columns;
                    }

                    columnsWidth = new float[viewColumns.Count];
                    measuredHeight = 0;
                    headerRowHeight = 0;
                    totalWidth = 0;

                    // Calculate the size of the cells.
                    for (int columnIndex = 0; columnIndex < columnsWidth.Length; columnIndex++)
                    {
                        SizeF headerCellSize = g.MeasureString(viewColumns[columnIndex], DailyCalendarView.headerFont);
                        headerRowHeight = Math.Max(headerRowHeight, headerCellSize.Height);

                        SizeF cellSize =
                            g.MeasureString(DailyCalendarView.GetColumnValue(Entry, viewColumns[columnIndex]),
                                            DailyCalendarView.itemFont);
                        measuredHeight = Math.Max(measuredHeight, cellSize.Height);

                        columnsWidth[columnIndex] = Math.Max(headerCellSize.Width, cellSize.Width);
                        totalWidth += columnsWidth[columnIndex]
                                      + DailyCalendarView.PADDING_LEFT + DailyCalendarView.PADDING_RIGHT;
                    }

                    // Adjust the size of the popup panel
                    ShowPopup((int)Math.Ceiling(totalWidth),
                              (int)Math.Ceiling(headerRowHeight + measuredHeight +
                                                2*(DailyCalendarView.PADDING_TOP + DailyCalendarView.PADDING_BOTTOM)));
                }
            }
        }
    }
}